use rand::Rng;
use std::cmp;
use strum::EnumIter;

use crate::asm::AsmCodeGenError;

#[derive(Debug, Clone)]
pub enum Code {
    File(String),
    Text(String),
    FnLabel(String),
    Label(String),
    Instr(Instruction),
    Raw(String),
    Pass, // 特殊占位 Code，生成 asm 时跳过该 Code 的转化
}

#[derive(Debug, Clone, PartialEq)]
pub enum StatementType {
    If,
    Return,
    For,
    While,
    Switch,
}

// 带单个返回目标的输出形式
#[derive(Debug, Clone)]
pub struct EvalOutput {
    pub ret_op: Operand,
    pub data_ty: Literal, // 用一个任意值字面量表述类型
    pub codes: Vec<Code>,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Register {
    GPR(GPR, RComponent),
}

impl Register {
    pub fn to_string(&self) -> String {
        match self {
            Register::GPR(gpr, rc) => gpr_component_name(gpr, rc),
        }
    }

    pub fn bytes_len(&self) -> usize {
        match self {
            Register::GPR(_, rcomponent) => rcomponent.bytes_len(),
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Operand {
    Register(Register),
    Immediate(Literal),
    StackTop,
    Memory {
        base: Option<Register>,
        offset: Option<i32>,
        index: Option<Register>,
        scale: Option<u8>,
    },
    Label(String),
}

impl Operand {
    pub fn is_imm(&self) -> bool {
        get_imm(&self).is_some()
    }

    pub fn to_string(&self) -> String {
        operand_to_string(&self)
    }

    pub fn bytes_len(&self) -> usize {
        operand_bytes_len(&self)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Literal {
    Num(Number),
    Str(String),
}

/// # 描述
/// 由于需要编译期计算，需要支持一些数值运算，并说明是否是有符号的，结构为 (`u8`/`u16`/`u32`/`u64`,是否带符号)
///
/// 统一采用 overflowing 逻辑，和 C 语言一样，但除 0 仍然会 `panic`，要自己判断，但也只是 warning 提示，不能终止
/// 算术运算 `add`,`sub`,`mul`,`div` 都是输出元组 (转换后的结果，是否存在 64 位溢出)
///
/// # 简易的隐式类型转换支持
/// 过程中，根据操作数的字长，决定输出操作数的字长，中间的计算都是转换为 `i64`/`u64` 计算，所以只有 neg 比较特殊
///
/// * 整形
///
/// 在表达式中 char,short,uchar,ushort 优先转 int
///
/// 当 int 与 uint 运算时转 uint，当 int/uint 与 long long 运算时转 long long
///
/// 当 long long 与 unsigned long long 运算时转 unsigned long long
#[derive(Debug, Clone, PartialEq)]
pub enum Number {
    U8(u8, bool),
    U16(u16, bool),
    U32(u32, bool),
    U64(u64, bool),
}

macro_rules! number_unaryop_c_promoted {
    ($name:ident,$closure:expr) => {
        pub fn $name(&self) -> Self {
            match &self {
                Number::U8(t, s) => Number::U32($closure(*t as u64) as u32, *s),
                Number::U16(t, s) => Number::U32($closure(*t as u64) as u32, *s),
                Number::U32(t, s) => Number::U32($closure(*t as u64) as u32, *s),
                Number::U64(t, s) => Number::U64($closure(*t as u64) as u64, *s),
            }
        }
    };
}

/// 提供两个闭包 closure1,closure2
/// closure1 用于无符号数操作
/// closure2 由于有符号数操作
macro_rules! number_binop_c_promoted_overflow {
    ($name:ident,$t1:ty,$closure1:expr,$t2:ty,$closure2:expr) => {
        pub fn $name(&self, rhs: &Self) -> (Self, bool) {
            match (
                self.bytes_len(),
                self.is_signed(),
                rhs.bytes_len(),
                rhs.is_signed(),
            ) {
                (4, true, 4, true) => {
                    // i32
                    let (res, of) = ($closure2)(self.promote() as $t2, rhs.promote() as $t2);
                    (Number::U32(res as u32, true), of)
                }
                (4, _, 4, _) => {
                    // u32
                    let (res, of) = ($closure1)(self.promote() as $t1, rhs.promote() as $t1);
                    (Number::U32(res as u32, false), of)
                }
                (1 | 2 | 4, _, 1 | 2 | 4, _) => {
                    let (res, of) = ($closure2)(self.promote() as $t2, rhs.promote() as $t2);
                    (Number::U32(res as u32, true), of)
                }
                (8, true, 8, true) => {
                    // i64
                    let (res, of) = ($closure2)(self.promote() as $t2, rhs.promote() as $t2);
                    (Number::U64(res as u64, true), of)
                }
                (8, _, 8, _) => {
                    // u64
                    let (res, of) = ($closure1)(self.promote() as $t1, rhs.promote() as $t1);
                    (Number::U64(res as u64, false), of)
                }
                (_, _, _, _) => {
                    let (res, of) = ($closure2)(self.promote() as $t2, rhs.promote() as $t2);
                    (Number::U32(res as u32, true), of)
                }
            }
        }
    };
}

macro_rules! number_binop_c_promoted {
    ($name:ident,$closure:expr) => {
        pub fn $name(&self, rhs: &Self) -> Self {
            match (
                self.bytes_len(),
                self.is_signed(),
                rhs.bytes_len(),
                rhs.is_signed(),
            ) {
                (4, true, 4, true) => Number::U32(
                    ($closure)(self.promote() as i64, rhs.promote() as i64) as u32,
                    true,
                ),
                (4, _, 4, _) => Number::U32(
                    ($closure)(self.promote() as i64, rhs.promote() as i64) as u32,
                    false,
                ),
                (4 | 8, true, 4 | 8, true) => Number::U64(
                    ($closure)(self.promote() as i64, rhs.promote() as i64) as u64,
                    true,
                ),
                (4 | 8, _, 4 | 8, _) => Number::U64(
                    ($closure)(self.promote() as i64, rhs.promote() as i64) as u64,
                    false,
                ),
                (_, _, _, _) => Number::U32(
                    ($closure)(self.promote() as i64, rhs.promote() as i64) as u32,
                    true,
                ),
            }
        }
    };
}

impl Number {
    number_unaryop_c_promoted! {not,|x : u64| !x}

    number_unaryop_c_promoted! {is_zero,|x : u64| x == 0}

    number_binop_c_promoted_overflow! {add,u64,|x : u64,y : u64| x.overflowing_add(y),i64,|x : i64,y : i64| x.overflowing_add(y)}

    number_binop_c_promoted_overflow! {sub,u64,|x : u64,y : u64| x.overflowing_sub(y),i64,|x : i64,y : i64| x.overflowing_sub(y)}

    number_binop_c_promoted_overflow! {mul,u64,|x : u64,y : u64| x.overflowing_mul(y),i64,|x : i64,y : i64| x.overflowing_mul(y)}

    number_binop_c_promoted_overflow! {div,u64,|x : u64,y : u64| x.overflowing_div(y),i64,|x : i64,y : i64| x.overflowing_div(y)}

    number_binop_c_promoted! {and,|x : i64,y : i64| x & y}

    number_binop_c_promoted! {or,|x : i64,y : i64| x | y}

    number_binop_c_promoted! {xor,|x : i64,y : i64| x ^ y}

    number_binop_c_promoted! {shl,|x : i64,y : i64| x << y}

    number_binop_c_promoted! {shr,|x : i64,y : i64| x >> y}

    pub fn neg(&self) -> Self {
        match self {
            Number::U8(t, _s) => Number::U32(-(*t as i32) as u32, true),
            Number::U16(t, _s) => Number::U32(-(*t as i32) as u32, true),
            Number::U32(t, _s) => Number::U32(-(*t as i32) as u32, true),
            Number::U64(t, _s) => Number::U64(-(*t as i64) as u64, true),
        }
    }

    pub fn bytes_len(&self) -> usize {
        match self {
            Number::U8(_, _) => 1,
            Number::U16(_, _) => 2,
            Number::U32(_, _) => 4,
            Number::U64(_, _) => 8,
        }
    }

    pub fn promote(&self) -> i64 {
        match self {
            Number::U8(t, _) => *t as i64,
            Number::U16(t, _) => *t as i64,
            Number::U32(t, _) => *t as i64,
            Number::U64(t, _) => *t as i64,
        }
    }

    pub fn is_signed(&self) -> bool {
        match &self {
            Number::U8(_, s) => *s,
            Number::U16(_, s) => *s,
            Number::U32(_, s) => *s,
            Number::U64(_, s) => *s,
        }
    }

    // 生成一个未定义值，供形如除0错误的表达式计算
    pub fn undefined() -> Self {
        // i32
        Number::U32(rand::rng().random(), true)
    }
}

macro_rules! literal_num {
    ($t:ident($num:expr)) => {
        Literal::Num(Number::$t($num))
    };
    ($t:ident($num:expr,$num1:expr)) => {
        Literal::Num(Number::$t($num, $num1))
    };
}

impl Literal {
    pub fn bytes_len(&self) -> usize {
        match self {
            Literal::Num(n) => n.bytes_len(),
            Literal::Str(t) => t.len(),
        }
    }
    pub fn to_string(&self) -> String {
        match self {
            Literal::Num(n) => match n {
                Number::U8(t, false) => t.to_string(),
                Number::U8(t, true) => (*t as i8).to_string(),
                Number::U16(t, false) => t.to_string(),
                Number::U16(t, true) => (*t as i16).to_string(),
                Number::U32(t, false) => t.to_string(),
                Number::U32(t, true) => (*t as i32).to_string(),
                Number::U64(t, false) => t.to_string(),
                Number::U64(t, true) => (*t as i64).to_string(),
            },
            Literal::Str(t) => t.to_string(),
        }
    }
    pub fn to_number(&self) -> Option<Number> {
        if let Self::Num(n) = self {
            Some(n.clone())
        } else {
            None
        }
    }
    pub fn is_signed(&self) -> Option<bool> {
        self.to_number().and_then(|x| Some(x.is_signed()))
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Instruction {
    Mov(Operand, Operand),  // dest ==> src
    Add(Operand, Operand),  // src + dest ==> src
    Sub(Operand, Operand),  // src - dest ==> src
    Mul(Operand),           // acc * src
    Div(Operand),           // ax = dx:ax / divisor,dx = dx:ax % divisor
    Inc(Operand),           // dest++
    Dec(Operand),           // dest--
    And(Operand, Operand),  // dest, src
    Or(Operand, Operand),   // dest, src
    Xor(Operand, Operand),  // dest, src
    Not(Operand),           // dest
    Neg(Operand),           // dest
    Shl(Operand, Operand),  // dest, count
    Shr(Operand, Operand),  // dest, count
    Cmp(Operand, Operand),  // left, right
    Test(Operand, Operand), // left, right
    Jmp(Operand),           // target
    Je(Operand),            // target
    Jne(Operand),           // target
    Call(Operand),          // function
    Ret,
    Push(Operand),
    Pop(Operand),
    Lea(Operand, Operand), // dest, src
    Sete(Operand),         // dest
    Imul(Operand),         // acc * src 有符号
    Idiv(Operand),         // ax = dx:ax / divisor,dx = dx:ax % divisor 有符号
    Cbtw,                  // 有符号除法的扩展准备 8 位
    Cwtd,                  // 16 位
    Cltd,                  // 32 位
    Cqto,                  // 64 位
}

// 批量定义Code转化函数 （无优化）
macro_rules! code_no_opt_gen_fn {
    ([0] => { $($name:ident => $instr:ident),* $(,)?}) => {
        $(
            pub fn $name() -> Self {
                Code::Instr(Instruction::$instr)
            }
        )*
    };
    ([1] => { $($name:ident => $instr:ident),* $(,)?}) => {
        $(
            pub fn $name(a: &Operand) -> Self {
                Code::Instr(Instruction::$instr(a.clone()))
            }
        )*
    };
    ([2] => { $($name:ident => $instr:ident),* $(,)?}) => {
        $(
            pub fn $name(a: &Operand,b : &Operand) -> Self {
                Code::Instr(Instruction::$instr(a.clone(),b.clone()))
            }
        )*
    };
}

impl Code {
    // 定义对应的参数数量的函数 [x] 中的 x 代表操作数个数
    code_no_opt_gen_fn! {
        [0] => {
            ret => Ret,
            cbtw => Cbtw,
            cwtd => Cwtd,
            cltd => Cltd,
            cqto => Cqto,
        }
    }
    code_no_opt_gen_fn! {
        [1] => {
            mul => Mul,
            imul => Imul,
            div => Div,
            idiv => Idiv,
            inc => Inc,
            dec => Dec,
            not => Not,
            neg => Neg,
            jmp => Jmp,
            je => Je,
            jne => Jne,
            call => Call,
            push => Push,
            pop => Pop,
            sete => Sete
        }
    }
    code_no_opt_gen_fn! {
        [2] => {
            add => Add,
            sub => Sub,
            and => And,
            xor => Xor,
            shl => Shl,
            shr => Shr,
            cmp => Cmp,
            test => Test,
            lea => Lea
        }
    }

    // 扩展符号位的便捷函数，对 a 的大小做自动的推断
    pub fn expand_sign_to_dx(a: &Operand) -> Result<Self, AsmCodeGenError> {
        match a.bytes_len() {
            1 => Ok(Code::cbtw()),
            2 => Ok(Code::cwtd()),
            4 => Ok(Code::cltd()),
            8 => Ok(Code::cqto()),
            _ => Err(AsmCodeGenError::WrongOperandSizeSuffix),
        }
    }

    // 执行在 asm 代码层面一些可能的优化，如 mov %eax,%eax 这种直接没有必要出现
    pub fn mov(a: &Operand, b: &Operand) -> Self {
        if a == b {
            Code::Pass
        } else {
            Code::Instr(Instruction::Mov(a.clone(), b.clone()))
        }
    }
}

impl Instruction {
    pub fn to_string(&self) -> Result<String, AsmCodeGenError> {
        match self {
            Instruction::Mov(a, b) => Ok(format!(
                "mov{}\t{},{}",
                size_suffix(cmp::min(a.bytes_len(), b.bytes_len()))?,
                a.to_string(),
                b.to_string()
            )),
            Instruction::Add(a, b) => Ok(format!(
                "add{}\t{},{}",
                size_suffix(cmp::min(a.bytes_len(), b.bytes_len()))?,
                a.to_string(),
                b.to_string()
            )),
            Instruction::Sub(a, b) => Ok(format!(
                "sub{}\t{},{}",
                size_suffix(cmp::min(a.bytes_len(), b.bytes_len()))?,
                a.to_string(),
                b.to_string()
            )),
            Instruction::Mul(a) => Ok(format!(
                "mul{}\t{}",
                size_suffix(a.bytes_len())?,
                a.to_string()
            )),
            Instruction::Div(a) => Ok(format!(
                "div{}\t{}",
                size_suffix(a.bytes_len())?,
                a.to_string()
            )),
            Instruction::Imul(a) => Ok(format!(
                "imul{}\t{}",
                size_suffix(a.bytes_len())?,
                a.to_string()
            )),
            Instruction::Idiv(a) => Ok(format!(
                "idiv{}\t{}",
                size_suffix(a.bytes_len())?,
                a.to_string()
            )),
            Instruction::Inc(a) => todo!(),
            Instruction::Dec(a) => todo!(),
            Instruction::And(a, b) => Ok(format!(
                "and{}\t{},{}",
                size_suffix(cmp::min(a.bytes_len(), b.bytes_len()))?,
                a.to_string(),
                b.to_string()
            )),
            Instruction::Or(a, b) => Ok(format!(
                "or{}\t{},{}",
                size_suffix(cmp::min(a.bytes_len(), b.bytes_len()))?,
                a.to_string(),
                b.to_string()
            )),
            Instruction::Xor(a, b) => Ok(format!(
                "xor{}\t{},{}",
                size_suffix(cmp::min(a.bytes_len(), b.bytes_len()))?,
                a.to_string(),
                b.to_string()
            )),
            Instruction::Not(a) => Ok(format!("not \t{}", a.to_string())),
            Instruction::Neg(a) => Ok(format!("neg \t{}", a.to_string())),
            Instruction::Shl(a, b) => Ok(format!(
                "shl{}\t{},{}",
                size_suffix(cmp::min(a.bytes_len(), b.bytes_len()))?,
                a.to_string(),
                b.to_string()
            )),
            Instruction::Shr(a, b) => Ok(format!(
                "shr{}\t{},{}",
                size_suffix(cmp::min(a.bytes_len(), b.bytes_len()))?,
                a.to_string(),
                b.to_string()
            )),
            Instruction::Cmp(a, b) => Ok(format!(
                "cmp{}\t{},{}",
                size_suffix(cmp::min(a.bytes_len(), b.bytes_len()))?,
                a.to_string(),
                b.to_string()
            )),
            Instruction::Test(a, b) => Ok(format!(
                "test{}\t{},{}",
                size_suffix(cmp::min(a.bytes_len(), b.bytes_len()))?,
                a.to_string(),
                b.to_string()
            )),
            Instruction::Jmp(a) => todo!(),
            Instruction::Je(a) => todo!(),
            Instruction::Jne(a) => todo!(),
            Instruction::Call(a) => todo!(),
            Instruction::Ret => Ok(format!("ret")),
            Instruction::Push(a) => Ok(format!("push\t{}", a.to_string())),
            Instruction::Pop(a) => Ok(format!("pop \t{}", a.to_string())),
            Instruction::Lea(a, b) => Ok(format!(
                "lea{}\t{},{}",
                size_suffix(cmp::min(a.bytes_len(), b.bytes_len()))?,
                a.to_string(),
                b.to_string()
            )),
            Instruction::Sete(a) => Ok(format!("sete\t{}", a.to_string())),
            Instruction::Cbtw => Ok(format!("cbtw")),
            Instruction::Cwtd => Ok(format!("cwtd")),
            Instruction::Cltd => Ok(format!("cltd")),
            Instruction::Cqto => Ok(format!("cqto")),
        }
    }
}
// 用寄存器编号寻找寄存器的名字，用 RComponent 指代一个寄存器可访问的内部结构，统一用 RAX，EAX，AX，AH，AL 来指代
#[derive(Debug, Clone, PartialEq, EnumIter)]
pub enum RComponent {
    AL,
    AH,
    AX,
    EAX,
    RAX,
}

impl RComponent {
    pub fn bytes_len(&self) -> usize {
        match self {
            RComponent::AL => 1,
            RComponent::AH => 1,
            RComponent::AX => 2,
            RComponent::EAX => 4,
            RComponent::RAX => 8,
        }
    }
}

#[derive(Debug, Clone, PartialEq, PartialOrd, EnumIter)]
pub enum GPR {
    RAX = 0,
    RBX = 1,
    RCX = 2,
    RDX = 3,
    RSI = 4,
    RDI = 5,
    RBP = 6,
    RSP = 7,
    R8 = 8,
    R9 = 9,
    R10 = 10,
    R11 = 11,
    R12 = 12,
    R13 = 13,
    R14 = 14,
    R15 = 15,
}

// 通用寄存器组件的名称
pub fn gpr_component_name(idx: &GPR, rc: &RComponent) -> String {
    let mut s = gpr_ori_name(&idx.clone());
    if idx < &GPR::R8 {
        //rax,eax,ax,ah,al
        match rc {
            RComponent::RAX => s,
            RComponent::EAX => {
                s.replace_range(0..1, "e");
                s
            }
            RComponent::AX => {
                s.remove(0);
                s
            }
            RComponent::AH => {
                s.remove(0);
                s.pop();
                s.push('h');
                s
            }
            RComponent::AL => {
                s.remove(0);
                s.pop();
                s.push('l');
                s
            }
        }
    } else {
        //%r8,%r8d,%r8w,%r8h,%r8l
        match rc {
            RComponent::RAX => s,
            RComponent::EAX => {
                s.push('d');
                s
            }
            RComponent::AX => {
                s.push('w');
                s
            }
            RComponent::AH => {
                s.push('h');
                s
            }
            RComponent::AL => {
                s.push('l');
                s
            }
        }
    }
}

// 通用寄存器整体的名字
pub fn gpr_ori_name(idx: &GPR) -> String {
    match idx {
        GPR::RAX => "rax".to_string(),
        GPR::RBX => "rbx".to_string(),
        GPR::RCX => "rcx".to_string(),
        GPR::RDX => "rdx".to_string(),
        GPR::RSI => "rsi".to_string(),
        GPR::RDI => "rdi".to_string(),
        GPR::RBP => "rbp".to_string(),
        GPR::RSP => "rsp".to_string(),
        GPR::R8 => "r8".to_string(),
        GPR::R9 => "r9".to_string(),
        GPR::R10 => "r10".to_string(),
        GPR::R11 => "r11".to_string(),
        GPR::R12 => "r12".to_string(),
        GPR::R13 => "r13".to_string(),
        GPR::R14 => "r14".to_string(),
        GPR::R15 => "r15".to_string(),
    }
}

pub fn operand_to_string(s: &Operand) -> String {
    match s {
        Operand::Register(register) => format!("%{}", register.to_string()),
        Operand::Immediate(literal) => format!("${}", literal.to_string()),
        Operand::Memory {
            base,
            offset,
            index,
            scale,
        } => todo!(),
        Operand::Label(_) => todo!(),
        Operand::StackTop => String::new(),
    }
}

pub fn operand_bytes_len(s: &Operand) -> usize {
    match s {
        Operand::Register(register) => register.bytes_len(),
        Operand::Immediate(literal) => literal.bytes_len(),
        Operand::Memory {
            base,
            offset,
            index,
            scale,
        } => todo!(),
        Operand::Label(_) => todo!(),
        Operand::StackTop => 4,
    }
}

pub fn size_suffix(u: usize) -> Result<&'static str, AsmCodeGenError> {
    match u {
        1 => Ok("b"),
        2 => Ok("w"),
        4 => Ok("l"),
        8 => Ok("q"),
        _ => Err(AsmCodeGenError::WrongOperandSizeSuffix),
    }
}

macro_rules! imm_num {
    ($num:expr) => {
        imm!(Literal::Num($num))
    };
}

macro_rules! imm {
    ($x : expr) => {
        Operand::Immediate($x)
    };
}

pub fn get_imm(l: &Operand) -> Option<Literal> {
    if let Operand::Immediate(r) = l {
        Some(r.clone())
    } else {
        None
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum RegIndex {
    AL,
    AH,
    AX,
    EAX,
    RAX,
    BL,
    BH,
    BX,
    EBX,
    RBX,
    CL,
    CH,
    CX,
    ECX,
    RCX,
    DL,
    DH,
    DX,
    EDX,
    RDX,
    SI,
    ESI,
    RSI,
    DI,
    EDI,
    RDI,
    BP,
    EBP,
    RBP,
    SP,
    ESP,
    RSP,
    R8L,
    R8H,
    R8W,
    R8D,
    R8,
    R9L,
    R9H,
    R9W,
    R9D,
    R9,
    R10L,
    R10H,
    R10W,
    R10D,
    R10,
    R11L,
    R11H,
    R11W,
    R11D,
    R11,
    R12L,
    R12H,
    R12W,
    R12D,
    R12,
    R13L,
    R13H,
    R13W,
    R13D,
    R13,
    R14L,
    R14H,
    R14W,
    R14D,
    R14,
    R15L,
    R15H,
    R15W,
    R15D,
    R15,
}

macro_rules! reg_op {
    ($ri:ident) => {
        reg_operand(&RegIndex::$ri)
    };
}

pub fn reg_operand(ri: &RegIndex) -> Operand {
    match ri {
        RegIndex::AL => Operand::Register(Register::GPR(GPR::RAX, RComponent::AL)),
        RegIndex::AH => Operand::Register(Register::GPR(GPR::RAX, RComponent::AH)),
        RegIndex::AX => Operand::Register(Register::GPR(GPR::RAX, RComponent::AX)),
        RegIndex::EAX => Operand::Register(Register::GPR(GPR::RAX, RComponent::EAX)),
        RegIndex::RAX => Operand::Register(Register::GPR(GPR::RAX, RComponent::RAX)),

        RegIndex::BL => Operand::Register(Register::GPR(GPR::RBX, RComponent::AL)),
        RegIndex::BH => Operand::Register(Register::GPR(GPR::RBX, RComponent::AH)),
        RegIndex::BX => Operand::Register(Register::GPR(GPR::RBX, RComponent::AX)),
        RegIndex::EBX => Operand::Register(Register::GPR(GPR::RBX, RComponent::EAX)),
        RegIndex::RBX => Operand::Register(Register::GPR(GPR::RBX, RComponent::RAX)),

        RegIndex::CL => Operand::Register(Register::GPR(GPR::RCX, RComponent::AL)),
        RegIndex::CH => Operand::Register(Register::GPR(GPR::RCX, RComponent::AH)),
        RegIndex::CX => Operand::Register(Register::GPR(GPR::RCX, RComponent::AX)),
        RegIndex::ECX => Operand::Register(Register::GPR(GPR::RCX, RComponent::EAX)),
        RegIndex::RCX => Operand::Register(Register::GPR(GPR::RCX, RComponent::RAX)),

        RegIndex::DL => Operand::Register(Register::GPR(GPR::RDX, RComponent::AL)),
        RegIndex::DH => Operand::Register(Register::GPR(GPR::RDX, RComponent::AH)),
        RegIndex::DX => Operand::Register(Register::GPR(GPR::RDX, RComponent::AX)),
        RegIndex::EDX => Operand::Register(Register::GPR(GPR::RDX, RComponent::EAX)),
        RegIndex::RDX => Operand::Register(Register::GPR(GPR::RDX, RComponent::RAX)),

        RegIndex::SI => Operand::Register(Register::GPR(GPR::RSI, RComponent::AX)),
        RegIndex::ESI => Operand::Register(Register::GPR(GPR::RSI, RComponent::EAX)),
        RegIndex::RSI => Operand::Register(Register::GPR(GPR::RSI, RComponent::RAX)),

        RegIndex::DI => Operand::Register(Register::GPR(GPR::RDI, RComponent::AX)),
        RegIndex::EDI => Operand::Register(Register::GPR(GPR::RDI, RComponent::EAX)),
        RegIndex::RDI => Operand::Register(Register::GPR(GPR::RDI, RComponent::RAX)),

        RegIndex::BP => Operand::Register(Register::GPR(GPR::RBP, RComponent::AX)),
        RegIndex::EBP => Operand::Register(Register::GPR(GPR::RBP, RComponent::EAX)),
        RegIndex::RBP => Operand::Register(Register::GPR(GPR::RBP, RComponent::RAX)),

        RegIndex::SP => Operand::Register(Register::GPR(GPR::RSP, RComponent::AX)),
        RegIndex::ESP => Operand::Register(Register::GPR(GPR::RSP, RComponent::EAX)),
        RegIndex::RSP => Operand::Register(Register::GPR(GPR::RSP, RComponent::RAX)),

        RegIndex::R8L => Operand::Register(Register::GPR(GPR::R8, RComponent::AL)),
        RegIndex::R8H => Operand::Register(Register::GPR(GPR::R8, RComponent::AH)),
        RegIndex::R8W => Operand::Register(Register::GPR(GPR::R8, RComponent::AX)),
        RegIndex::R8D => Operand::Register(Register::GPR(GPR::R8, RComponent::EAX)),
        RegIndex::R8 => Operand::Register(Register::GPR(GPR::R8, RComponent::RAX)),

        RegIndex::R9L => Operand::Register(Register::GPR(GPR::R9, RComponent::AL)),
        RegIndex::R9H => Operand::Register(Register::GPR(GPR::R9, RComponent::AH)),
        RegIndex::R9W => Operand::Register(Register::GPR(GPR::R9, RComponent::AX)),
        RegIndex::R9D => Operand::Register(Register::GPR(GPR::R9, RComponent::EAX)),
        RegIndex::R9 => Operand::Register(Register::GPR(GPR::R9, RComponent::RAX)),

        RegIndex::R10L => Operand::Register(Register::GPR(GPR::R10, RComponent::AL)),
        RegIndex::R10H => Operand::Register(Register::GPR(GPR::R10, RComponent::AH)),
        RegIndex::R10W => Operand::Register(Register::GPR(GPR::R10, RComponent::AX)),
        RegIndex::R10D => Operand::Register(Register::GPR(GPR::R10, RComponent::EAX)),
        RegIndex::R10 => Operand::Register(Register::GPR(GPR::R10, RComponent::RAX)),

        RegIndex::R11L => Operand::Register(Register::GPR(GPR::R11, RComponent::AL)),
        RegIndex::R11H => Operand::Register(Register::GPR(GPR::R11, RComponent::AH)),
        RegIndex::R11W => Operand::Register(Register::GPR(GPR::R11, RComponent::AX)),
        RegIndex::R11D => Operand::Register(Register::GPR(GPR::R11, RComponent::EAX)),
        RegIndex::R11 => Operand::Register(Register::GPR(GPR::R11, RComponent::RAX)),

        RegIndex::R12L => Operand::Register(Register::GPR(GPR::R12, RComponent::AL)),
        RegIndex::R12H => Operand::Register(Register::GPR(GPR::R12, RComponent::AH)),
        RegIndex::R12W => Operand::Register(Register::GPR(GPR::R12, RComponent::AX)),
        RegIndex::R12D => Operand::Register(Register::GPR(GPR::R12, RComponent::EAX)),
        RegIndex::R12 => Operand::Register(Register::GPR(GPR::R12, RComponent::RAX)),

        RegIndex::R13L => Operand::Register(Register::GPR(GPR::R13, RComponent::AL)),
        RegIndex::R13H => Operand::Register(Register::GPR(GPR::R13, RComponent::AH)),
        RegIndex::R13W => Operand::Register(Register::GPR(GPR::R13, RComponent::AX)),
        RegIndex::R13D => Operand::Register(Register::GPR(GPR::R13, RComponent::EAX)),
        RegIndex::R13 => Operand::Register(Register::GPR(GPR::R13, RComponent::RAX)),

        RegIndex::R14L => Operand::Register(Register::GPR(GPR::R14, RComponent::AL)),
        RegIndex::R14H => Operand::Register(Register::GPR(GPR::R14, RComponent::AH)),
        RegIndex::R14W => Operand::Register(Register::GPR(GPR::R14, RComponent::AX)),
        RegIndex::R14D => Operand::Register(Register::GPR(GPR::R14, RComponent::EAX)),
        RegIndex::R14 => Operand::Register(Register::GPR(GPR::R14, RComponent::RAX)),

        RegIndex::R15L => Operand::Register(Register::GPR(GPR::R15, RComponent::AL)),
        RegIndex::R15H => Operand::Register(Register::GPR(GPR::R15, RComponent::AH)),
        RegIndex::R15W => Operand::Register(Register::GPR(GPR::R15, RComponent::AX)),
        RegIndex::R15D => Operand::Register(Register::GPR(GPR::R15, RComponent::EAX)),
        RegIndex::R15 => Operand::Register(Register::GPR(GPR::R15, RComponent::RAX)),
    }
}

// C语言隐式转换并警告溢出
macro_rules! implicit_conv_w {
    ($x:expr,$t:ty,$loc:expr) => {
        $x.try_into().or_else(|e| {
            let after = $x as $t;
            println!(
                "Woverflow: Implicit conversion : number {} change value to {}. 
                    Err = {}.
                    Token location = {}"
                , $x, after, e, $loc
            );
            Ok(after)
        })?
    };
    ($x:expr,$t:ty) => {
        $x.try_into().or_else(|e| {
            let after = $x as $t;
            println!(
                "Woverflow: Implicit conversion : number {} change value to {}. 
                    Err = {}."
                , $x, after, e
            );
            Ok(after)
        })?
    };
}

macro_rules! w_operation_sign_conv {
    ($x:expr,$loc:expr) => {
        println!(
            "Wsign-conversion: Signed number is implicitly promoted to unsigned number, which may change sign of the result. Result is {:?}.
                Token location = {}",
            $x,$loc
        )
    };
}

macro_rules! w_operation_overflow {
    ($x:expr,$loc:expr) => {
        println!(
            "Woverflow: Overflow in expression. Result is {:?}. 
                Token location = {}",
            $x,$loc
        )
    };
}

macro_rules! w_division_by_zero {
    ($x:expr,$loc:expr) => {
        println!(
            "Wundefined: Division by zero is undefined. Result is {:?}. 
                Token location = {}",
            $x,$loc
        )
    };
}
